using System;
using System.IO;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Storage;

namespace MauiApp.Services
{
    /// <summary>
    /// 日志辅助类，提供统一的日志记录功能
    /// </summary>
    public static class LogHelper
    {
        private static ILogger _logger;
        private static readonly object _lock = new object();

        /// <summary>
        /// 获取日志文件路径（跨平台可写）
        /// </summary>
        public static string LogFilePath
        {
            get
            {
                var appData = FileSystem.Current.AppDataDirectory;
                string appLogFolder = Path.Combine(appData, "MauiAppLogs");
                Directory.CreateDirectory(appLogFolder);
                string logFileName = $"app_{DateTime.Now:yyyy-MM-dd}.log";
                return Path.Combine(appLogFolder, logFileName);
            }
        }

        /// <summary>
        /// 获取或设置日志记录器实例
        /// </summary>
        public static ILogger Logger
        {
            get
            {
                if (_logger == null)
                {
                    lock (_lock)
                    {
                        if (_logger == null)
                        {
                            var factory = LoggerFactory.Create(builder =>
                            {
                                // 控制台日志
                                builder.AddConsole();

                                // 文件日志
                                builder.AddFileLogger(options =>
                                {
                                    options.FilePath = LogFilePath;
                                    options.Append = true;             // 追加到现有文件
                                    options.MaxFileSize = 1024 * 1024; // 1MB
                                });

#if DEBUG
                                builder.SetMinimumLevel(LogLevel.Debug);
#else
                                builder.SetMinimumLevel(LogLevel.Information);
#endif
                            });

                            // 固定非空分类名
                            _logger = factory.CreateLogger("MauiApp");
                        }
                    }
                }
                return _logger;
            }
            set { _logger = value; }
        }

        private class FileLoggerOptions
        {
            public string FilePath { get; set; } = string.Empty;
            public bool Append { get; set; }
            public int MaxFileSize { get; set; }
        }

        private static ILoggingBuilder AddFileLogger(this ILoggingBuilder builder, Action<FileLoggerOptions> configure)
        {
            var options = new FileLoggerOptions();
            configure(options);
            builder.AddProvider(new FileLoggerProvider(options));
            return builder;
        }

        private class FileLoggerProvider : ILoggerProvider
        {
            private readonly FileLoggerOptions _options;
            private readonly object _fileLock = new object();

            public FileLoggerProvider(FileLoggerOptions options)
            {
                _options = options;
                var directory = Path.GetDirectoryName(_options.FilePath);
                if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
            }

            public ILogger CreateLogger(string categoryName) => new FileLogger(_options, _fileLock);
            public void Dispose() { }
        }

        private class FileLogger : ILogger
        {
            private readonly FileLoggerOptions _options;
            private readonly object _fileLock;
            private long _currentFileSize = 0;

            public FileLogger(FileLoggerOptions options, object fileLock)
            {
                _options = options;
                _fileLock = fileLock;

                if (!string.IsNullOrWhiteSpace(_options.FilePath) && File.Exists(_options.FilePath))
                {
                    _currentFileSize = new System.IO.FileInfo(_options.FilePath).Length;
                }
            }

            IDisposable ILogger.BeginScope<TState>(TState state) => null;

            public bool IsEnabled(LogLevel logLevel)
            {
#if !DEBUG
                if (logLevel == LogLevel.Debug) return false;
#endif
                return true;
            }

            void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
            {
                if (!IsEnabled(logLevel) || formatter == null) return;

                string message = formatter(state, exception);
                if (string.IsNullOrWhiteSpace(message)) return;
                if (string.IsNullOrWhiteSpace(_options.FilePath)) return;

                string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{logLevel}] {message}{(exception != null ? $"\n{exception}" : "")}\n";

                lock (_fileLock)
                {
                    try
                    {
                        if (_options.MaxFileSize > 0 && _currentFileSize >= _options.MaxFileSize)
                        {
                            string? basePath = Path.GetDirectoryName(_options.FilePath);
                            string fileName = Path.GetFileNameWithoutExtension(_options.FilePath);
                            string extension = Path.GetExtension(_options.FilePath);

                            if (!string.IsNullOrWhiteSpace(basePath))
                            {
                                int counter = 1;
                                string newFilePath;
                                do
                                {
                                    newFilePath = Path.Combine(basePath, $"{fileName}_{counter}{extension}");
                                    counter++;
                                }
                                while (File.Exists(newFilePath) && new System.IO.FileInfo(newFilePath).Length >= _options.MaxFileSize);

                                _options.FilePath = newFilePath;
                                _currentFileSize = 0;
                            }
                        }

                        using (var writer = new StreamWriter(_options.FilePath, _options.Append, System.Text.Encoding.UTF8))
                        {
                            writer.Write(logEntry);
                        }

                        _currentFileSize += System.Text.Encoding.UTF8.GetByteCount(logEntry);
                    }
                    catch
                    {
                        // 忽略日志写入错误
                    }
                }
            }
        }

        // 公共日志方法（空字符串防御）
        public static void Debug(string message)
        {
            if (string.IsNullOrWhiteSpace(message)) return;
            Logger.LogDebug(message);
        }

        public static void Debug(string format, params object[] args)
        {
            if (string.IsNullOrWhiteSpace(format)) return;
            Logger.LogDebug(format, args);
        }

        public static void Info(string message)
        {
            if (string.IsNullOrWhiteSpace(message)) return;
            Logger.LogInformation(message);
        }

        public static void Info(string format, params object[] args)
        {
            if (string.IsNullOrWhiteSpace(format)) return;
            Logger.LogInformation(format, args);
        }

        public static void Warn(string message)
        {
            if (string.IsNullOrWhiteSpace(message)) return;
            Logger.LogWarning(message);
        }

        public static void Warn(string format, params object[] args)
        {
            if (string.IsNullOrWhiteSpace(format)) return;
            Logger.LogWarning(format, args);
        }

        public static void Error(string message)
        {
            if (string.IsNullOrWhiteSpace(message)) return;
            Logger.LogError(message);
        }

        public static void Error(string format, params object[] args)
        {
            if (string.IsNullOrWhiteSpace(format)) return;
            Logger.LogError(format, args);
        }

        public static void Error(string message, Exception exception)
        {
            if (string.IsNullOrWhiteSpace(message)) return;
            Logger.LogError(exception, message);
        }
    }
}